package com.nowar.frame.proxy;

import com.google.common.collect.Lists;
import com.nowar.common.service.MessageProvide;
import com.nowar.exception.ServiceProxyException;
import com.nowar.frame.annotation.HttpProxy;
import com.nowar.frame.contxt.RequestContext;
import com.nowar.frame.entity.RequestBodyProxy;
import com.nowar.frame.result.BaseHandlerResult;
import com.nowar.util.HttpClientUtils;
import com.nowar.util.SpringContextUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URI;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * 代理类
 *
 * @Author: 谢无殇。
 * @Date : 2023-01-14 21:31
 */
public class HttpProxyInvocationHandler implements InvocationHandler {
    private static final Logger logger = LogManager.getLogger(HttpClientUtils.class);
    private Class clazz;
    private HttpProxy httpProxy;
    private String serviceName;
    private Map<String, Method> methodMap = new HashMap<>();

    public HttpProxyInvocationHandler(Class clazz) {
        this.clazz = clazz;
        init();
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return request(method, args);
    }

    private Object request(Method method, Object[] args) throws ServiceProxyException {
        // 获取请求上下文
        RequestContext context = getRequestContext(method, args);
        // 发送请求
        Object response = doRequest(context);
        // 处理请求结果
        handlerResponse(response, args);
        if (method.getReturnType().getName().equals("void")) {
            return method.getReturnType().cast(null);
        }
        return response;
    }

    private void handlerResponse(Object response, Object[] args) throws ServiceProxyException {
        for (Object object : args) {
            // 结果处理
            if (object instanceof BaseHandlerResult) {
                BaseHandlerResult handlerResult = (BaseHandlerResult) object;
                handlerResult.handlerResult(response);
            }
        }
    }

    private Object doRequest(RequestContext context) throws ServiceProxyException {
        if (httpProxy.cse()) {
            return doCse(context);
        }
        return doHttp(context);
    }

    private Object doHttp(RequestContext context) throws ServiceProxyException {
        RestTemplateBuilder templateBuilder = new RestTemplateBuilder()
                .setConnectTimeout(context.getHttpConnect())
                .setReadTimeout(context.getHttpTime())
                //可设置多个拦截器
                .interceptors(SpringContextUtils.getBean(ClientHttpRequestInterceptor.class));

        RestTemplate template = templateBuilder.build();
        URI uri = URI.create(context.getUrl());
        HttpEntity httpEntity = new HttpEntity(context.getRequest(), context.getHeaders());

        ResponseEntity exchange = template.exchange(uri, context.getHttpMethod(), httpEntity, context.getReturnType());
        if (exchange == null) {
            System.out.println("响应结果为空.");
        }
        if (exchange.getStatusCodeValue() != HttpStatus.OK.value()) {
            throw new ServiceProxyException("请求结果异常.");
        }
        return exchange.getBody();
    }

    private Object doCse(RequestContext context) {
        return null;
    }

    private RequestContext getRequestContext(Method method, Object[] args) {
        //解析占位符
        String valueByProperties = SpringContextUtils.getBean(MessageProvide.class).getValueProperties(serviceName);
        System.out.println(valueByProperties);
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        //todo
        String api = postMapping.name();
        String url = "http://" + httpProxy.host() + ":" + httpProxy.port() + api;
        RequestContext context = RequestContext.builder()
                .cse(httpProxy.cse())
                .url(url)
                .httpConnect(Duration.ofMillis(httpProxy.httpConnect()))
                .httpTime(Duration.ofMillis(httpProxy.httpTime()))
                .returnType(method.getReturnType())
                .build();
        if (postMapping != null) {
            context.setHttpMethod(HttpMethod.POST);
        }
        if (getMapping != null) {
            context.setHttpMethod(HttpMethod.GET);
        }
        Parameter[] parameters = method.getParameters();
        Map<Parameter, Object> map = new HashMap<>();
        if (parameters.length != 0) {
            for (int i = 0; i < parameters.length; i++) {
                map.put(parameters[i], args[i]);
            }
        }
        //处理请求参数
        map.forEach((key, value) -> {
            Annotation requestBody = key.getAnnotation(RequestBody.class);
            Annotation requestParam = key.getAnnotation(RequestParam.class);
            Annotation requestHeader = key.getAnnotation(RequestHeader.class);
            if (requestBody != null) {
                if (value instanceof RequestBodyProxy) {
                    context.setRequest((RequestBodyProxy) value);
                }
            }
            if (requestParam != null) {
                if (value instanceof Map) {
                    context.setParams((Map) value);
                }
            }
            if (requestHeader != null) {
                if (value instanceof Map) {
                    HttpHeaders httpHeaders = new HttpHeaders();
                    httpHeaders.setAll((Map) value);
                }
                if (value instanceof HttpHeaders) {
                    HttpHeaders httpHeaders = (HttpHeaders) value;
                    context.setHeaders(httpHeaders);
                }
            }
        });
        if (context.getHeaders() == null) {
            context.setHeaders(getHttpHeaders());
        }
        return context;
    }

    private HttpHeaders getHttpHeaders() {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.put("Accept", Lists.newArrayList("application/json"));
        httpHeaders.put("Content-Type", Lists.newArrayList("application/json"));
        return httpHeaders;
    }

    /**
     * 初始化数据
     */
    private void init() {
        this.httpProxy = (HttpProxy) this.clazz.getAnnotation(HttpProxy.class);
        serviceName = httpProxy.serviceName();
    }
}
